//
//  Toast.swift
//  FrameProduct
//
//  Created by delegate on 2024/2/3.
//
import UIKit


/// 按照UE文档中设计定义的提示框
///
/// 示例代码1：
/// 通过链式调用，当前页面弹出一个内容为“请阅读用户服务协议和隐私政策并勾选”的提示框，并有一个确认按钮，需要用户点击确认后，才会消失
///
///      Toast.dismiss(for: self, style: .info)
///          .with(message: "当前地区服务暂未开通～")
///          .userInteractionEnabled(false)
///          .position(.center, offset: CGPoint(x: 0, y: -30))
///          .bind(action: Toast.Action(title: "确定"))
///          .show()
///
/// 示例代码2（菊花加载中）:
///
///     let toast = Toast.with(message: "正在获取中", style: .activity)
///         .show()
///     DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
///         toast.dismiss()
///         Toast.with(message: "验证码已通过短信，发送到你的手机，请查收")
///             .show()
///     }
///
public protocol ToastCustomable: UIView {
    var intrinsicContentSize: CGSize { get }
    
    func closeToast(withClosure closure: @escaping () -> Void)
}

public struct Toast: Alertable {
    
    public struct Action {
        let title: String
        var closure: (() -> Void)? = nil
    }
    
    public enum Position {
        case center
        case top
        case bottom
    }
    
    public enum Style {
        /// 文本样式的文本提示 page_floating 和 page_floating2‘
        case info
        /// 警告样式的文本提示，不会常驻
        case warning
        /// 错误样式的文本提示，不会常驻
        case error
        /// 加载菊花，常驻，需主动关闭
        case activity
        /// 自定义样式，常驻，需主动关闭
        case custom(view: ToastCustomable)
        /// 带图片的提示信息
        /// 成功样式，不会常驻
        case imageInfo(image: UIImage?, message: String)
    }
    
    var hud: MyProgressHUD
    
    @discardableResult
    public static func with(title: String? = nil, message: String?, style: Style = .info) -> Self {
        return Toast(hud: MyProgressHUD.createWithStyle(style, title: title, message: message))
    }
    
    @discardableResult
    public static func with(customView: ToastCustomable) -> Self {
        return self.with(title: nil, message: nil, style: .custom(view: customView))
    }
    
    @discardableResult
    public static func with(image: UIImage?, message: String) -> Self {
        return self.with(title: nil, message: nil, style: .imageInfo(image: image, message: message))
    }
    
    /// 移动弹框当前的偏移量
    ///
    /// - Parameters:
    ///   - offset: 要移动的偏移量
    /// - Returns:
    ///   - 返回alert 自身
    @discardableResult
    public func position(_ position: Position = .center, offset: CGPoint? = nil) -> Self {
        
        // 顶部和底部Y，默认为10的偏移量
        var _offset = offset ?? .zero
        if offset == nil {
            switch position {
            case .top:
                _offset = CGPoint(x: 0, y: 30)
            case .bottom :
                _offset = CGPoint(x: 0, y: -60)
            case  .center:
                _offset = .zero
            }
        }
        self.hud.offset = _offset
        self.hud.position = position
        return self
    }
    @discardableResult
    public func userInteractionEnabled(_ isEnabled: Bool) -> Self {
        self.hud.isUserInteractionEnabled = isEnabled
        return self
    }
    @discardableResult
    public func message(_ message: String?) -> Self {
        self.hud.detailsLabel.text = message
        return self
    }
    @discardableResult
    public func title(_ title: String?) -> Self {
        self.hud.label.text = title
        return self
    }
    @discardableResult
    public func identifier(_ identifier: String?) -> Self {
        self.hud.accessibilityIdentifier = identifier
        return self
    }
    
    public var identifier: String? {
        return self.hud.accessibilityIdentifier
    }
    
    @discardableResult
    public func onRemoved(_ closure: (() -> Void)?) -> Self {
        self.hud.onRemovedClosure = closure
        return self
    }
}

public extension AlertActionBindable where Self == Toast {
    func bind(action: Action) -> Self {
        self.hud.setAction(action)
        self.hud.isHideAfterDisplay = false
        return self
    }
}

public extension AlertPresentable where Self == Toast {
    @discardableResult
    func show(on convertible: ViewConvertible? = nil, completion: (() -> Void)? = nil) -> Self {
        let view = try! convertible?.asView() ?? UIApplication.lxs.topViewController?.view ?? UIApplication.lxs.topWindow
        self.hud.frame = view.bounds
        view.addSubview(self.hud)
        self.hud.show(animated: true)
        DispatchQueue.main.async {
            if let completion = completion {
                completion()
            }
        }
        if self.hud.isHideAfterDisplay {
            self.hud.hide(animated: true, afterDelay: 3)
        }
        return self
    }
    
    func dismiss(animated: Bool = true) {
        self.hud.hide(animated: animated)
    }
    
    @discardableResult
    static func dismiss(for convertible: ViewConvertible?, style: Toast.Style) -> Self.Type {
        do {
            let _convertible = convertible ?? UIApplication.lxs.topViewController
            if let view = try _convertible?.asView(),
               let huds = MyProgressHUD.huds(for: view) {
                huds.forEach { hud in
                    if style == hud.style {
                        hud.hide(animated: false)
                    }
                }
            }
        } catch {
            print(error)
        }
        return self
    }
}

public extension Toast {
    @discardableResult
    func visible(_ isShow: Bool) -> Self {
        if isShow {
            self.show()
        }
        else {
            self.dismiss()
        }
        return self
    }
    
    /// 在当前keyWindow 上显示
    @discardableResult
    func showOnWindow() -> Self {
        self.show(on: UIApplication.lxs.topWindow)
    }
}

extension Toast.Style: Equatable {
    public static func == (lhs: Toast.Style, rhs: Toast.Style) -> Bool {
        switch (lhs, rhs) {
        case (.custom(let view1), .custom(let view2)):
          return view1 == view2
        case (.info, .info):
          return true
        case (.imageInfo(let image, let message), .imageInfo(let image1, let message1)):
          return image == image1 && message == message1
        case (.error, .error):
          return true
        case (.warning, .warning):
          return true
        case (.activity, .activity):
            return true
        default:
          return false
        }
    }
}
